package com.ly.gateway.filter;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.jwt.JWTUtil;
import cn.hutool.jwt.signers.JWTSigner;
import cn.hutool.jwt.signers.JWTSignerUtil;
import com.ly.common.core.constant.TokenConstants;
import com.ly.common.core.utils.ServletUtils;
import com.ly.common.core.utils.StringUtils;
import com.ly.gateway.config.properties.IgnoreWhiteProperties;
import com.ly.gateway.config.properties.TokenProperties;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.addOriginalRequestUrl;

/**
 * 全局网关鉴权
 *
 * @Auth luoyong
 */
@Component
@RequiredArgsConstructor
public class LyGlobalFilter implements GlobalFilter, Ordered {

    private static final Logger log = LoggerFactory.getLogger(LyGlobalFilter.class);

    private final IgnoreWhiteProperties ignoreWhite;
    private final StringRedisTemplate redisService;
    private final TokenProperties tokenProperties;

    public final static String PREFIX_GATEWAY_PATH = "/api";

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String url = request.getURI().getPath();
        log.info("当前路径为：{}", url);
        // 白名单直接放行
        String relUrl = StrUtil.replace(url, PREFIX_GATEWAY_PATH, "");
        if (StringUtils.matches(relUrl, ignoreWhite.getWhites())) {
            log.info("当前放行路径为：{}", url);
            return chain.filter(exchange);
        }
        // token验证
        String token = request.getHeaders().getFirst(tokenProperties.getHeader());
        if (StrUtil.isEmpty(token)) {
            return unauthorizedResponse(exchange, "token为空");
        }
        if (!token.startsWith(tokenProperties.getTokenPrefix())) {
            return unauthorizedResponse(exchange, "token格式错误");
        }
        token = token.replaceFirst(tokenProperties.getTokenPrefix(), "");
        JWTSigner signer = JWTSignerUtil.hs512(tokenProperties.getSecret().getBytes());
        JSONObject claims = JWTUtil.parseToken(token).setSigner(signer).getPayload().getClaimsJson();
        // 解析对应的权限以及用户信息
        String uuid = claims.getStr(TokenConstants.LOGIN_USER_KEY);
        boolean islogin = redisService.hasKey(TokenConstants.LOGIN_TOKEN_KEY + uuid);
        log.info("当前请求的token为：{},url为：{}", token, url);
        if (!islogin) {
            return unauthorizedResponse(exchange, "登录状态已过期");
        }
        // 1. 重写StripPrefix(获取真实的URL)
        addOriginalRequestUrl(exchange, request.getURI());
        return chain.filter(exchange.mutate().request(request.mutate().build()).build());
    }

    /**
     * 未授权提示返回
     */
    private Mono<Void> unauthorizedResponse(ServerWebExchange exchange, String msg) {
        log.error("[鉴权异常处理]请求路径:{}", exchange.getRequest().getPath());
        return ServletUtils.webFluxResponseWriter(exchange.getResponse(), msg, HttpStatus.UNAUTHORIZED.value());
    }

    /**
     * 最高优先级
     *
     * @return
     */
    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE;
    }
}